#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "vdev"
#define CLASS_NAME "vclass"

static int major;
static struct class *vdev_class;
static struct cdev vdev_cdev;
static struct device *vdev_device; // 新增设备指针

// 设备数据结构
struct vdev_data {
    char *buffer;
    size_t size;
    struct device *dev; // 每个设备实例保存设备指针
};

// 打开设备
static int vdev_open(struct inode *inode, struct file *file)
{
    struct vdev_data *data;

    data = kmalloc(sizeof(struct vdev_data), GFP_KERNEL);
    if (!data) {
        pr_err("Failed to allocate memory\n");
        return -ENOMEM;
    }

    data->buffer = kmalloc(1024, GFP_KERNEL);
    if (!data->buffer) {
        pr_err("Failed to allocate buffer\n");
        kfree(data);
        return -ENOMEM;
    }
    data->size = 0;
    data->dev = vdev_device; // 保存设备指针

    file->private_data = data;

    dev_info(data->dev, "Device opened\n");
    return 0;
}

// 释放设备
static int vdev_release(struct inode *inode, struct file *file)
{
    struct vdev_data *data = file->private_data;

    if (data) {
        kfree(data->buffer);
        kfree(data);
    }

    dev_info(vdev_device, "Device closed\n");
    return 0;
}

// 读取设备
static ssize_t vdev_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
    struct vdev_data *data = file->private_data;

    if (*pos >= data->size)
        return 0;

    if (copy_to_user(buf, data->buffer + *pos, data->size - *pos))
        return -EFAULT;

    *pos += data->size - *pos;

    dev_dbg(data->dev, "Read %zu bytes\n", data->size);
    return data->size;
}

// 写入设备
static ssize_t vdev_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
    struct vdev_data *data = file->private_data;

    if (count > 1024) {
        dev_warn(data->dev, "Write size too big: %zu\n", count);
        return -EFBIG;
    }

    if (copy_from_user(data->buffer, buf, count))
        return -EFAULT;

    data->size = count;
    *pos = count;

    dev_info(data->dev, "Received %zu bytes\n", count);
    return count;
}

// 文件操作结构体
static const struct file_operations vdev_fops = {
    .owner = THIS_MODULE,
    .open = vdev_open,
    .release = vdev_release,
    .read = vdev_read,
    .write = vdev_write,
};

// 模块初始化
static int __init vdev_init(void)
{
    dev_t dev;
    int ret;

    // 动态分配主设备号
    ret = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
    if (ret < 0) {
        pr_err("Failed to allocate device number\n");
        return ret;
    }
    major = MAJOR(dev);

    // 创建设备类（修正参数）
    vdev_class = class_create(CLASS_NAME);
    if (IS_ERR(vdev_class)) {
        unregister_chrdev_region(dev, 1);
        return PTR_ERR(vdev_class);
    }

    // 初始化字符设备
    cdev_init(&vdev_cdev, &vdev_fops);
    vdev_cdev.owner = THIS_MODULE;

    // 添加字符设备
    ret = cdev_add(&vdev_cdev, dev, 1);
    if (ret < 0) {
        class_destroy(vdev_class);
        unregister_chrdev_region(dev, 1);
        return ret;
    }

    // 创建设备节点并保存设备指针
    vdev_device = device_create(vdev_class, NULL, dev, NULL, DEVICE_NAME);
    if (IS_ERR(vdev_device)) {
        cdev_del(&vdev_cdev);
        class_destroy(vdev_class);
        unregister_chrdev_region(dev, 1);
        return PTR_ERR(vdev_device);
    }

    dev_info(vdev_device, "Device initialized\n");
    return 0;
}

// 模块退出
static void __exit vdev_exit(void)
{
    dev_t dev = MKDEV(major, 0);

    device_destroy(vdev_class, dev);
    class_destroy(vdev_class);
    cdev_del(&vdev_cdev);
    unregister_chrdev_region(dev, 1);

    pr_info("Device unloaded\n");
}

module_init(vdev_init);
module_exit(vdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple virtual device driver demo");
